﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Liquid.Windows.Commands {
	[Designer(typeof(Liquid.Windows.Design.Commands.CommandBinderDesigner))]
	[ProvideProperty("Command", typeof(object))]
	public abstract class CommandBinder : Component, IExtenderProvider {
		protected internal abstract bool CanExtend(object extendee);
		protected internal abstract CommandBinding CreateBinding(object extendee);

		internal CommandSet CommandSet {
			get {
				var target = m_CommandSet == null
					? null
					: m_CommandSet.Target;
				return (CommandSet)target;
			}
			set {
				if (value == null)
					m_CommandSet = null;
				else
					m_CommandSet = new WeakReference(value);
			}
		}
		private WeakReference m_CommandSet;

		bool IExtenderProvider.CanExtend(object extendee) {
			return this.CanExtend(extendee);
		}

		Dictionary<object, CommandBinding> m_Bindings = new Dictionary<object, CommandBinding>();
		public Command GetCommand(object extendee) {
			CommandBinding binding;
			if (m_Bindings.TryGetValue(extendee, out binding)) {
				return binding.Command;
			} else {
				return null;
			}
		}
		public void SetCommand(object extendee, Command command) {
			CommandBinding binding;
			m_Bindings.TryGetValue(extendee, out binding);
			try {
				if (command != null && binding == null) {
					binding = this.CreateBinding(extendee);
					m_Bindings.Add(extendee, binding);
					command.AddBinding(binding);
				} else if (command == null && binding != null) {
					m_Bindings.Remove(extendee);
					binding.Dispose();
				} else if (command != null && binding != null) {
					if (binding.Command != null) {
						binding.Command.RemoveBinding(binding);
						binding.Dispose();
					}
					command.AddBinding(binding);
				} else { // if (command == null && binding == null)
				}
			} catch {
				throw;
			}
		}
		public bool ShouldSerializeCommand(object extendee) {
			CommandBinding binding;
			if (m_Bindings.TryGetValue(extendee, out binding)) {
				return binding.Command != null;
			} else {
				return false;
			}
		}
	}
	public abstract class CommandBinder<T> : CommandBinder
		where T : class
	{
		protected abstract bool CanExtend(T extendee);
		protected abstract CommandBinding CreateBinding(T extendee);

		protected internal sealed override bool CanExtend(object extendee) {
			T extendeeT = extendee as T;
			if (extendeeT != null)
				return this.CanExtend(extendeeT);
			else
				return false;
		}

		protected internal override CommandBinding CreateBinding(object extendee) {
			T extendeeT = extendee as T;
			if (extendeeT != null)
				return this.CreateBinding(extendeeT);
			else
				throw new NotSupportedException();
		}
	}
}
